package com.sky.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sky.dto.OrdersCancelDTO;
import com.sky.dto.OrdersConfirmDTO;
import com.sky.dto.OrdersPageQueryDTO;
import com.sky.dto.OrdersRejectionDTO;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.mapper.OrderAdminMapper;
import com.sky.result.PageResult;
import com.sky.service.OrderService;
import com.sky.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
    private final OrderAdminMapper orderAdminMapper;

    @Override
    public OrderStatisticsVO selectStatistics() {
        List<Integer> list = orderAdminMapper.selectStatistics();
        OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();
        AtomicInteger count1 = new AtomicInteger();
        AtomicInteger count2 = new AtomicInteger();
        AtomicInteger count3 = new AtomicInteger();
        list.forEach(num -> {
            if (num == Orders.TO_BE_CONFIRMED) {
                count1.set(count1.get() + 1);
            }
            if (num == Orders.CONFIRMED) {
                count2.set(count2.get() + 1);
            }
            if (num == Orders.DELIVERY_IN_PROGRESS) {
                count3.set(count3.get() + 1);
            }
        });
        orderStatisticsVO.setToBeConfirmed(count1.get());
        orderStatisticsVO.setConfirmed(count2.get());
        orderStatisticsVO.setDeliveryInProgress(count3.get());
        return orderStatisticsVO;
    }

    @Override
    public PageResult selectConditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {

        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        List<Orders> Orderslist = orderAdminMapper.selectConditionSearch(ordersPageQueryDTO);
        PageInfo<Orders> pageInfo = new PageInfo<>(Orderslist);
        return new PageResult(pageInfo.getTotal(), pageInfo.getList());
    }

    @Override
    public OrderVO selectDetails(Long id) {
        OrderVO orders = orderAdminMapper.getOrdersById(id);
        List<OrderDetail> orderDetailList = orderAdminMapper.getOrderDetailById(id);
        orders.setOrderDetailList(orderDetailList);
        return orders;
    }

    @Override
    public void updateDelivery(Long id) {
        Orders orders = new Orders();
        orders.setId(id);
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);
        orderAdminMapper.updateDelivery(orders);
    }

    @Override
    public void confirmOrder(OrdersConfirmDTO ordersConfirmDTO) {
        Orders orders = new Orders();
        orders.setId(ordersConfirmDTO.getId());
        orders.setStatus(Orders.CONFIRMED);
        orderAdminMapper.updateDelivery(orders);
    }

    @Override
    public void rejectionOrder(OrdersRejectionDTO ordersRejectionDTO) {
        Orders orders = new Orders();
        orders.setId(ordersRejectionDTO.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setRejectionReason(ordersRejectionDTO.getRejectionReason());
        orderAdminMapper.updateDelivery(orders);
    }

    @Override
    public void completeOrder(Long id) {
        Orders orders = new Orders();
        orders.setId(id);
        orders.setStatus(Orders.COMPLETED);
        orderAdminMapper.updateDelivery(orders);
    }

    @Override
    public void cancelOrder(OrdersCancelDTO ordersCancelDTO) {
        Orders orders = new Orders();
        orders.setId(ordersCancelDTO.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setRejectionReason(ordersCancelDTO.getCancelReason());
        orderAdminMapper.updateDelivery(orders);
    }

    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        List<Map<String, Object>> mapList = orderAdminMapper.selectStatisticsBetweenOrderTime(begin, end);
        ArrayList<String> timeList = new ArrayList<>();
        ArrayList<String> amountList = new ArrayList<>();
        mapList.forEach(map -> {
            String timeStr = (String) map.get("order_time_format");
            timeList.add(timeStr);
            BigDecimal amount = (BigDecimal) map.get("sum_amount");
            amountList.add(amount.toString());
        });
        String joinedTime = String.join(",", timeList);
        String joinedAmount = String.join(",", amountList);
        TurnoverReportVO turnoverReportVO = new TurnoverReportVO();
        turnoverReportVO.setDateList(joinedTime);
        turnoverReportVO.setTurnoverList(joinedAmount);
        return turnoverReportVO;
    }

    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        List<Map<String, Object>> mapList = orderAdminMapper.selectStatisticsBetweenCreateTime(begin, end);
        ArrayList<String> timeList = new ArrayList<>();
        ArrayList<String> userDayList = new ArrayList<>();
        ArrayList<String> userAllList = new ArrayList<>();
        mapList.forEach(map -> {
            String timeStr = (String) map.get("create_time_format");
            timeList.add(timeStr);
            Long userDay = (Long) map.get("count_day");
            userDayList.add(userDay.toString());
            Long userAll = (Long) map.get("count_all");
            userAllList.add(userAll.toString());
        });
        String joinedTime = String.join(",", timeList);
        String joinedUserDay = String.join(",", userDayList);
        String joinedUserAll = String.join(",", userAllList);
        UserReportVO userReportVO = new UserReportVO();
        userReportVO.setDateList(joinedTime);
        userReportVO.setTotalUserList(joinedUserAll);
        userReportVO.setNewUserList(joinedUserDay);
        return userReportVO;
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        List<Map<String, Object>> mapList = orderAdminMapper.selectStatisticsBetweenOrdersTime(begin, end);

        String timeJoined = mapList.stream().map(item -> (String) item.get("order_time_format")).collect(Collectors.joining(","));
        List<Long> countEffective = mapList.stream().map(item -> (Long) item.get("count_effective")).collect(Collectors.toList());
        List<Long> countAll = mapList.stream().map(item -> (Long) item.get("count_all")).collect(Collectors.toList());

        Optional<Long> countEffectiveSum = countEffective.stream().reduce(Long::sum);
        Long aCountEffective = 0L;
        if (countEffectiveSum.isPresent()) {
            aCountEffective = countEffectiveSum.get();
        }

        Optional<Long> countAllSum = countAll.stream().reduce(Long::sum);
        Long aCountAll = 0L;
        if (countAllSum.isPresent()) {
            aCountAll = countAllSum.get();
        }

        String collectEffective = countEffective.stream().map(Object::toString).collect(Collectors.joining(","));
        String collectAll = countAll.stream().map(Object::toString).collect(Collectors.joining(","));
        Double orderCompletionRate = aCountEffective.doubleValue() / aCountAll.doubleValue();

        OrderReportVO orderReportVO = new OrderReportVO();
        orderReportVO.setDateList(timeJoined);
        orderReportVO.setOrderCountList(collectAll);
        orderReportVO.setValidOrderCountList(collectEffective);
        orderReportVO.setTotalOrderCount(Math.toIntExact(aCountAll));
        orderReportVO.setValidOrderCount(Math.toIntExact(aCountEffective));
        orderReportVO.setOrderCompletionRate(orderCompletionRate);

        return orderReportVO;
    }

    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        List<Map<String, Object>> mapList = orderAdminMapper.selectTop10(begin, end);
        String nameJoined = mapList.stream().map(item -> (String) item.get("name")).collect(Collectors.joining(","));
        String sumJoined = mapList.stream().map(item -> (BigDecimal) item.get("sum"))
                .map(BigDecimal::intValue)
                .map(Object::toString).collect(Collectors.joining(","));
        SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();
        salesTop10ReportVO.setNameList(nameJoined);
        salesTop10ReportVO.setNumberList(sumJoined);
        return salesTop10ReportVO;
    }

    @Override
    public void export(HttpServletResponse response) {
        try {
            InputStream stream = this.getClass().getClassLoader().getResourceAsStream("template/temp.xlsx");
            assert stream != null;
            Workbook wb = WorkbookFactory.create(stream);
            Sheet sheet1 = wb.getSheetAt(0);

            LocalDate now = LocalDate.now();
            LocalDate end = now.plusDays(-1L);
            LocalDate begin = end.plusDays(-30L);
            String time = "生成时间:" + begin + "至" + end;

            ExcelVO excelVO = orderAdminMapper.selectExcelData(begin, end);

            // 概览数据
            Row row2 = sheet1.getRow(1);
            Cell cell1 = row2.getCell(1);
            cell1.setCellValue(time);
            Row row4 = sheet1.getRow(3);
            Cell cell43 = row4.getCell(2);
            cell43.setCellValue(excelVO.getSumAmount());
            Cell cell45 = row4.getCell(4);
            cell45.setCellValue(excelVO.getOrdersEffectiverate());
            Cell cell47 = row4.getCell(6);
            cell47.setCellValue(excelVO.getCountDayuser());

            Row row5 = sheet1.getRow(4);
            Cell cell53 = row5.getCell(2);
            cell53.setCellValue(excelVO.getCountEffective());
            Cell cell55 = row5.getCell(4);
            cell55.setCellValue(excelVO.getAvgAmount());

            // 明细数据
            List<ExcelDetailsVO> list = orderAdminMapper.selectExcelDetailsVO(begin, end);
            for (int i = 0; i < list.size(); i++) {
                Row row = sheet1.getRow(7 + i);
                ExcelDetailsVO excelDetailsVO = list.get(i);
                for (int j = 0; j < 6; j++) {
                    Cell cell = row.getCell(1 + j);
                    switch (1 + j) {
                        case 1 -> cell.setCellValue(String.valueOf(excelDetailsVO.getDate()));
                        case 2 -> cell.setCellValue(excelDetailsVO.getAmountDay());
                        case 3 -> cell.setCellValue(excelDetailsVO.getCountEffective());
                        case 4 -> cell.setCellValue(excelDetailsVO.getOrdersEffectiverate());
                        case 5 -> cell.setCellValue(excelDetailsVO.getAvgAmount());
                        case 6 -> cell.setCellValue(excelDetailsVO.getCountDayuser());
                    }
                }
            }
            ServletOutputStream outputStream = response.getOutputStream();
            wb.write(outputStream);
        } catch (Exception e) {
            log.error("导出excel失败", e);
        }
    }
}
